package com.copm.ifm.servers.sys.service.impl.staff;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.copm.ifm.base.api.pojo.PageDTO;
import com.copm.ifm.base.api.pojo.PageVO;
import com.copm.ifm.base.api.util.CollectionUtils;
import com.copm.ifm.base.basic.ServiceResponse;
import com.copm.ifm.base.basic.constant.DbConstants;
import com.copm.ifm.base.basic.enums.ResponseCodeEnum;
import com.copm.ifm.base.basic.exception.ServiceException;
import com.copm.ifm.base.basic.pojo.vo.SysStaffAllVO;
import com.copm.ifm.base.basic.util.AuthUtils;
import com.copm.ifm.base.basic.util.DateUtils;
import com.copm.ifm.base.basic.util.ValidatorUtils;
import com.copm.ifm.base.service.mp.page.PageProxy;
import com.copm.ifm.servers.sys.dto.SysStaffDTO;
import com.copm.ifm.servers.sys.entity.*;
import com.copm.ifm.servers.sys.mapper.role.SysRoleMapper;
import com.copm.ifm.servers.sys.mapper.staff.SysStaffMapper;
import com.copm.ifm.servers.sys.mapper.staff.SysStaffRoleMapper;
import com.copm.ifm.servers.sys.mapping.SysStaffMapping;
import com.copm.ifm.servers.sys.service.project.SysProjectAuthService;
import com.copm.ifm.servers.sys.service.project.SysProjectService;
import com.copm.ifm.servers.sys.service.role.SysRoleMenuService;
import com.copm.ifm.servers.sys.service.staff.SysStaffMenuService;
import com.copm.ifm.servers.sys.service.staff.SysStaffRoleService;
import com.copm.ifm.servers.sys.service.staff.SysStaffService;
import com.copm.ifm.servers.sys.util.RedisServer4Staff;
import com.copm.ifm.servers.sys.vo.SysRoleVO;
import com.copm.ifm.servers.sys.vo.SysStaffVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 租户员工表 服务实现类
 *
 * @author zzf
 * @since 2020-12-22
 */
@Service
public class SysStaffServiceImpl extends ServiceImpl<SysStaffMapper, SysStaff> implements SysStaffService {

    @Resource
    SysStaffMapper sysStaffMapper;

    @Resource
    SysRoleMapper sysRoleMapper;

    @Resource
    SysStaffRoleMapper sysStaffRoleMapper;

    @Resource
    SysStaffRoleService sysStaffRoleService;

    @Resource
    SysStaffMenuService sysStaffMenuService;

    @Resource
    SysRoleMenuService sysRoleMenuService;

    @Resource
    SysProjectService sysProjectService;

    @Resource
    SysProjectAuthService sysProjectAuthService;

    /**
     * 添加账号的默认密码：123456，加密之后即为字符串入库
     */
    private static final String PASSWORD = "e10adc3949ba59abbe56e057f20f883e";

    @Override
    public SysStaffAllVO getAllInfoById(Long id) {
        return baseMapper.selectAllInfoById(id);
    }

    @Override
    public PageVO<SysStaffVO> selectForPage(PageDTO<SysStaffDTO> pageDTO) {
        if ("name".equals(pageDTO.getSortName())) {
            pageDTO.setSortName("CONVERT( staffName USING gbk )");
        }
        PageVO<SysStaffVO> proxy = PageProxy.proxy(baseMapper::selectForPage, pageDTO);
        List<SysStaffVO> records = proxy.getRecords();
        ServiceResponse<List<SysStaffVO>> success = new ServiceResponse<>(records, ResponseCodeEnum.SUCCESS);
        proxy.setRecords(success.getData());
        return proxy;
    }

    @Override
    public SysStaffVO selectVoById(Long id) {
        return sysStaffMapper.selectVoById(id);
    }

    @Override
    public SysStaff selectById(Long id) {
        return sysStaffMapper.selectById(id);
    }

    @Override
    public SysStaff selectCurrentUserInfo() {
        return sysStaffMapper.selectById(AuthUtils.getCurrentUserId());
    }

    @Override
    public int updateDeleted(Long id) {
        SysStaff sysStaff = new SysStaff();
        sysStaff.setId(id);
        sysStaff.setDeleted(DbConstants.DEFAULT_YES);
        int i = sysStaffMapper.updateById(sysStaff);
        RedisServer4Staff.addStaffIdName(sysStaff);
        return i;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveStaff(SysStaffDTO entity) {
        if (!StringUtils.isEmpty(entity.getPhone())) {
            if (!ValidatorUtils.isMobile(entity.getPhone())) {
                throw new ServiceException("请输入正确的手机号码，请修改后提交");
            }
        }
        if (!ValidatorUtils.isUserName(entity.getUsername())) {
            throw new ServiceException("请输入正确的账号(英文数字或者下划线)，请修改后提交");
        }

        Long userId = AuthUtils.getCurrentUserId();
        if (StringUtils.isEmpty(entity.getUsername())) {
            throw new ServiceException("新增系统账号不能为空，请修改后提交");
        }
        List<SysStaff> staffList = baseMapper.selectList(new LambdaQueryWrapper<SysStaff>()
                .eq(SysStaff::getUsername, entity.getUsername())
                .eq(SysStaff::getDeleted, DbConstants.DEFAULT_NO)
        );
        if (staffList.size() > 0) {
            throw new ServiceException("新增系统账号【" + entity.getUsername() + "】已存在，请修改后提交");
        }
        if (!StringUtils.isEmpty(entity.getTenantId())) {
            List<SysStaff> sysStaffsList = baseMapper.selectList(new LambdaQueryWrapper<SysStaff>()
                    .eq(SysStaff::getTenantId, entity.getTenantId())
                    .eq(SysStaff::getType, DbConstants.SUPPER_ADMIN)
            );
            if (sysStaffsList.size() > 1) {
                throw new ServiceException("只能存在一个超级管理员账号，请修改后提交");
            }
        }
        SysStaff sysStaff = SysStaffMapping.INSTANCE.dto2po(entity);
        sysStaff.setCreateBy(userId);
        sysStaff.setUpdateBy(userId);
        sysStaff.setPassword(PASSWORD);
        sysStaff.setTenantId(StringUtils.isEmpty(entity.getTenantId()) ? AuthUtils.getCurrentUserTenant() : entity.getTenantId());
        sysStaff.setCreateTime(new Date());
        sysStaffMapper.insert(sysStaff);
        Long staffId = sysStaff.getId();

        if (!StringUtils.isEmpty(entity.getRoleList())) {
            if (entity.getRoleList().size() < 1) {
                throw new ServiceException("新增系统角色不能为空，请修改后提交");
            }
            List<SysStaffRole> staffRoleList = new ArrayList<>();
            List<SysRole> allSysRole = new ArrayList<>();
            entity.getRoleList().forEach(
                    s -> {
                        SysStaffRole sysStaffRole = new SysStaffRole();
                        sysStaffRole.setStaffId(staffId);
                        SysRole sysRole = sysRoleMapper.selectOne(new LambdaQueryWrapper<SysRole>()
                                .eq(SysRole::getId, s)
                                .select(SysRole::getId)
                        );
                        allSysRole.add(sysRole);
                        if (ObjectUtils.isEmpty(sysRole)) {
                            throw new ServiceException("系统中没有相对应的角色名称，请先添加此角色权限");
                        }
                        sysStaffRole.setRoleId(sysRole.getId());
                        staffRoleList.add(sysStaffRole);
                    }
            );
            //第一次添加菜单数据到账号菜单下
            addStaffMenu(allSysRole, staffId);
            sysStaffRoleMapper.insertStaffRollList(staffRoleList);
        }
        RedisServer4Staff.addStaffIdName(sysStaff);
    }

    private void addStaffMenu(List<SysRole> allSysRole, Long staffId) {
        List<Long> sysRoles = allSysRole.stream().map(SysRole::getId).collect(Collectors.toList());
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuService.list(new LambdaQueryWrapper<SysRoleMenu>()
                .in(SysRoleMenu::getRoleId, sysRoles));
        Map<Long, List<String>> roleMap = sysRoleMenuList.stream()
                .collect(
                        Collectors.toMap(
                                SysRoleMenu::getMenuId,
                                SysRoleMenu::getOperations,
                                CollectionUtils::unionDistinct
                        )
                );
        Set<Map.Entry<Long, List<String>>> entries = roleMap.entrySet();
        List<SysStaffMenu> staffMenus = new ArrayList<>();
        for (Map.Entry<Long, List<String>> entry : entries) {
            SysStaffMenu sysStaffMenu = new SysStaffMenu();
            sysStaffMenu.setStaffId(staffId);
            sysStaffMenu.setMenuId(entry.getKey());
            sysStaffMenu.setOperations(entry.getValue());
            sysStaffMenu.setCreateTime(new Date());
            sysStaffMenu.setCreateBy(AuthUtils.getCurrentUserId());
            staffMenus.add(sysStaffMenu);
        }
        sysStaffMenuService.saveBatch(staffMenus);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateStaff(SysStaffDTO entity) {
        if (!ValidatorUtils.isMobile(entity.getPhone())) {
            throw new ServiceException("请输入正确的手机号码，请修改后提交");
        }
        if (!ValidatorUtils.isUserName(entity.getUsername())) {
            throw new ServiceException("请输入正确的账号(英文数字或者下划线)，请修改后提交");
        }
        String username = entity.getUsername();
        List<SysStaff> sysStaffs = new ArrayList<>();
        SysStaff sysStaff = new SysStaff();
        if (entity.getId() != null) {
            sysStaff = sysStaffMapper.selectOne(new LambdaQueryWrapper<SysStaff>()
                    .eq(SysStaff::getId, entity.getId())
                    .select());
        }
        if (entity.getUsername() != null) {
            sysStaffs = sysStaffMapper.selectList(new LambdaQueryWrapper<SysStaff>()
                    .eq(SysStaff::getUsername, username)
                    .select());
        }
        //有一个值且username与库中的值不相等
        if (!username.equals(sysStaff.getUsername()) && sysStaffs.size() > 0) {
            throw new ServiceException("添加的账号名" + username + "已存在，请修改后再次提交");
        }
        //如果修改了角色，那么也需要修改用户角色关联表
        //查找租户id为0的角色列表，角色列表的角色名要能和后台角色对的上，对不上这里就会报错
        Set<Integer> staffsSet = new HashSet<>(entity.getRoleList());
        List<SysRoleVO> sysRoleV = sysRoleMapper.selectSysByTenantId(0);
        List<SysStaffRole> list = new ArrayList<>();
        sysStaffRoleService.remove(new LambdaQueryWrapper<SysStaffRole>().eq(SysStaffRole::getStaffId, entity.getId()));
        staffsSet.forEach(x -> {
            List<SysRoleVO> sysRoleVOList = sysRoleV.stream()
                    .filter(s -> x.equals(s.getId()))
                    .collect(Collectors.toList());
            if (sysRoleVOList.size() == 0) {
                throw new ServiceException("该角色名" + x + "不是后台对应的角色");
            }
            Long roleId = sysRoleVOList.get(0).getId();
            SysStaffRole sysStaffRole = new SysStaffRole();
            sysStaffRole.setId(entity.getStaffRoleId());
            sysStaffRole.setStaffId(entity.getId());
            sysStaffRole.setRoleId(roleId);
            list.add(sysStaffRole);
        });
        sysStaffRoleService.saveBatch(list);

        // 修改用户信息
        SysStaff staff = SysStaffMapping.INSTANCE.dto2po(entity);
        staff.setUpdateBy(AuthUtils.getCurrentUserId());
        staff.setUpdateTime(new Date());
        int i = sysStaffMapper.updateById(staff);

        // 修改成功后，同步修改redis缓存
        RedisServer4Staff.addStaffIdName(staff);
        return i;
    }

    @Override
    public int updateByName(SysStaff entity) {
        entity.setUpdateBy(AuthUtils.getCurrentUserId());
        entity.setUpdateTime(new Date());
        return sysStaffMapper.updateByName(entity);
    }

    @Override
    public List<String> getOverduePro(Long tenantId) {
        List<SysProjectAuth> projectAuths = sysProjectAuthService.list(new LambdaQueryWrapper<SysProjectAuth>()
                .eq(SysProjectAuth::getTenantId, tenantId)
                .eq(SysProjectAuth::getIsOverdue, DbConstants.DEFAULT_NO)
        );
        List<Long> overdueProjectIdList = projectAuths.stream()
                .filter(s -> s.getOverdueTime() > DateUtils.differentDaysByMillisecond(new Date(), s.getAuthEndTime()))
                .map(SysProjectAuth::getProjectId)
                .collect(Collectors.toList());
        return sysProjectService.list(new LambdaQueryWrapper<SysProject>()
                .in(SysProject::getId, overdueProjectIdList)
        ).stream().map(SysProject::getName).collect(Collectors.toList());
    }

    @Override
    public List<SysStaff> testList() {
        return baseMapper.testList();
    }
}
